/*============================================================================*/
/*                                                                            */
/* findpars.c                                                                 */
/*                                                                            */
/* This program may help you with finding the best values of the thresholds   */
/* angleThres, gradSizeThresh and apparenceThresh for the images you are going*/
/* to process. In a given image, the program simply detects the corners in    */
/* a cycle with varying values of the thresholds, and compares the set of     */
/* found corners with a given reference solution. The best obtained solution  */
/* is determined and the values of the thresholds giving this solution are    */
/* considered as optimal for this and similar images.                         */
/*                                                                            */
/* (c) Eduard Sojka, 2002                                                     */
/*                                                                            */
/*============================================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cordet.h"
#include "utils.h"
#define  MAX_NUM_OF_CORNER_COORDS 20000  /* maximal number of coords we accept*/
#define  LINE_LENGTH 256

/*----------------------------------------------------------------------------*/

#define freeMem \
  if (byteImage  != NULL) free(byteImage);\
  if (floatImage != NULL) free(floatImage);\
  if (corners    != NULL) free(corners);\
  if (refSol     != NULL) free(refSol);\

/*----------------------------------------------------------------------------*/
/* The function readScriptFile reads and analyses the script file. It returns */
/* the values of parameters that were set in the script file.                 */

int readScriptFile( char *scriptFileName,
    char *imageFileName, char *refCornerListFileName, int *halfPsgMaskSize,
    int *numAngleSteps,  float *initAngleThresh,  float *angleThreshStep,
    int *numGradSzSteps, float *initGradSzThresh, float *gradSzThreshStep,
    int *numApparSteps,  float *initApparThresh,  float *apparThreshStep,
    float *meanGradSizeThresh, float *inertiaRadiusThresh, 
    float *sigmaD, float *sigmaR, int *halfExtMaskSize, int *options ){

    FILE *inp; char atom[LINE_LENGTH];
    if((inp = fopen( scriptFileName, "rt" )) != NULL){
      readAtom(inp,atom); if (strcmp(atom, "findpars") != 0 ) return -2;
      if (readAtom(inp,imageFileName) != 0) return -3;
      if (readAtom(inp,refCornerListFileName) != 0) return -4;
      if (readAtom(inp,atom) != 0) return  -5; *halfPsgMaskSize    = atoi(atom);
      if (readAtom(inp,atom) != 0) return  -6; *numAngleSteps      = atoi(atom);
      if (readAtom(inp,atom) != 0) return  -7; *initAngleThresh    = atof(atom);
      if (readAtom(inp,atom) != 0) return  -8; *angleThreshStep    = atof(atom);
      if (readAtom(inp,atom) != 0) return  -9; *numGradSzSteps     = atoi(atom);
      if (readAtom(inp,atom) != 0) return -10; *initGradSzThresh   = atof(atom);
      if (readAtom(inp,atom) != 0) return -11; *gradSzThreshStep   = atof(atom);
      if (readAtom(inp,atom) != 0) return -12; *numApparSteps      = atoi(atom);
      if (readAtom(inp,atom) != 0) return -13; *initApparThresh    = atof(atom);
      if (readAtom(inp,atom) != 0) return -14; *apparThreshStep    = atof(atom);
      if (readAtom(inp,atom) != 0) return -15; *meanGradSizeThresh = atof(atom);
      if (readAtom(inp,atom) != 0) return -16; *inertiaRadiusThresh= atof(atom);
      if (readAtom(inp,atom) != 0) return -17; *sigmaD             = atof(atom);
      if (readAtom(inp,atom) != 0) return -18; *sigmaR             = atof(atom);
      if (readAtom(inp,atom) != 0) return -19; *halfExtMaskSize    = atoi(atom);
      if (readAtom(inp,atom) != 0) return -20; *options            = atoi(atom);
      fclose(inp); return 0;
    } else return -1;
}
/*----------------------------------------------------------------------------*/

int main( int argc, char **argv ) {

    char   imageFileName[LINE_LENGTH], refCornerListFileName[LINE_LENGTH];
    unsigned char *byteImage;
    float *floatImage;
    int    xImageSize, yImageSize, numImagePixels,
           halfPsgMaskSize, halfExtMaskSize, options, i;
    int   *corners, numCorners, *refSol, refSolLen;
    int    numAngleSteps, numGradSzSteps, numApparSteps,
           an, gr, ap, problem;
    float  gradSzThresh, angleThresh, apparThresh, meanGradSzThresh,
           inertiaRadiusThresh, sigmaD, sigmaR;
    float  initAngleThresh, angleThreshStep, optAngleThresh,
           initGradSzThresh, gradSzThreshStep, optGradSzThresh,
           initApparThresh, apparThreshStep, optApparThresh;
    int    nFound, nMissed, nFalse, nMultiple, totErr, minTotErr, nMins;
    float  locErr, minLocErr;

    if (argc != 2){
        printf( "\nsyntax:\n\n" );
        printf( "  findpars file\n\n" );
        printf( "  The 'file' contains a script for the program. You should\n");
        printf( "  obtain the script files 'find1.scr', 'find2.scr', and\n");
        printf( "  'find3.scr' along with this program. You can also create\n");
        printf( "  your own script files.\n\n");
        printf( "example: findpars find1.scr\n\n");
        return( -1 );
    }

    printf("\n");
    printf("===============================================================\n");
    printf("|     Finding the parameters for the VSB corner detector      |\n");
    printf("===============================================================\n");

    if ((problem = readScriptFile( argv[1],
        imageFileName, refCornerListFileName, &halfPsgMaskSize,
        &numAngleSteps, &initAngleThresh, &angleThreshStep,
        &numGradSzSteps, &initGradSzThresh, &gradSzThreshStep,
        &numApparSteps, &initApparThresh, &apparThreshStep,
        &meanGradSzThresh, &inertiaRadiusThresh, &sigmaD, &sigmaR,
        &halfExtMaskSize, &options)) != 0 ){
           printf("  Problem with the script file '%s' (line %i).\n\n",
                     argv[1], (-problem-1)); exit(-1);
    }

    byteImage = loadImageFromTGA(imageFileName, &xImageSize, &yImageSize);
    if (byteImage == NULL){
        printf("  Problems with loading the image from '%s'.\n", imageFileName);
        exit(-1);
    }

    numImagePixels = xImageSize*yImageSize;
    floatImage = malloc(numImagePixels * sizeof(floatImage[0]));
    corners    = malloc(MAX_NUM_OF_CORNER_COORDS* sizeof(corners[0]));
    refSol     = malloc(MAX_NUM_OF_CORNER_COORDS* sizeof(refSol[0]));
    if ((floatImage == NULL)||(corners == NULL)||(refSol == NULL)){
        printf("  Not enough memory for solving the problem.\n");
        freeMem;  exit(-1);
    }

    refSolLen = loadCornerList( refCornerListFileName, refSol,
                                MAX_NUM_OF_CORNER_COORDS );

    if (refSolLen == -1){
        printf("Cannot open ref. corner list '%s'.\n", refCornerListFileName);
        freeMem; return(-1);
    }
    if (refSolLen == -2){
        printf("Too many corners in '%s'.\n", refCornerListFileName);
        freeMem; return(-1);
    }

    printf("\n");
    printf("  The image from '%s' is now being processed.\n\n", imageFileName );
    for (i = 0; i < numImagePixels; i ++) floatImage[i] = byteImage[i];

    minTotErr = 0x7fffffff; minLocErr = 9999999.9;

    angleThresh = initAngleThresh;
    for (an = 0; an < numAngleSteps; an++, angleThresh += angleThreshStep){
      gradSzThresh = initGradSzThresh;
      for (gr = 0; gr < numGradSzSteps; gr++, gradSzThresh += gradSzThreshStep){
        apparThresh  = initApparThresh;
        for (ap = 0; ap < numApparSteps; ap++, apparThresh += apparThreshStep){
          printf("  ang=%5.3f", angleThresh );
          printf("  grad=%5.2f", gradSzThresh );
          printf("  appar=%5.2f", apparThresh );

          numCorners = detectCorners( floatImage, xImageSize, yImageSize,
            halfPsgMaskSize, angleThresh, gradSzThresh, apparThresh,
            meanGradSzThresh, inertiaRadiusThresh, sigmaD, sigmaR,
            halfExtMaskSize, options, corners, MAX_NUM_OF_CORNER_COORDS );

          if (numCorners >= 0){
            printf("  cors=%4i", numCorners);
            totErr = evaluateDetection( corners, numCorners, refSol, refSolLen,
                     &nFound, &nMissed, &nFalse, &nMultiple, &totErr, &locErr );
            printf("  Err=%4i/%5.3f\n", totErr, locErr);
            if (totErr < minTotErr){
              minTotErr = totErr; minLocErr = locErr;
              optAngleThresh = angleThresh;
              optGradSzThresh  = gradSzThresh;
              optApparThresh = apparThresh;
              nMins = 1;
            } else if (totErr == minTotErr){
                       nMins++;
                       if (locErr < minLocErr){
                          minLocErr = locErr;
                          optAngleThresh = angleThresh;
                          optGradSzThresh  = gradSzThresh;
                          optApparThresh = apparThresh;
                       }
                   }
          }
          else printf("  Not enough memory or small array for corners.\n");
        }
      }
    }

    printf("\n");
    printf("  Best solution:%3i times occured", nMins);
    printf(" totErr=%4i, min locErr=%5.3f\n", minTotErr, minLocErr);
    printf("\n");
    printf("  Optimal angle size threshold:    %8.3f\n", optAngleThresh);
    printf("  Optimal gradient size threshold: %8.3f\n", optGradSzThresh);
    printf("  Optimal apparence threshold:     %8.3f\n", optApparThresh);
    printf("\n");
    freeMem;
    printf("===============================================================\n");
    printf("\n");

    return 0;
}
/*============================================================================*/

